namespace Warehouse

open System.Windows
open System.Collections.ObjectModel
open System.Data
open System.Windows.Data
open System
open System.Net.Mail
open System.IO
open FSharp.Windows

type InvoiceController(repository : DataModel.Repository) = 
    inherit Controller<InvoiceEvents, InvoiceModel>()

    let mutable invoiceModified = false

    override this.InitModel model = 
        model.Items <- ObservableCollection()
        model.Last <- Nullable 20

    override this.Dispatcher = function
        | Search -> Sync this.Search
        | Edit -> Async this.Edit
        | Save -> Sync this.Save
        | PreviewLineItemDelete cancel -> Sync(this.PreviewLineItemDelete cancel)
        | DeleteLineItem -> Sync this.DeleteLineItem
        | AddLineItem -> Sync this.AddLineItem
        | SelectedInvoiceChanged(previous, _) -> Sync(fun _ -> this.SelectedInvoiceChanged previous)
        | LineItemModified column -> Sync(this.LineItemModified column)
        | Print printType -> Sync(this.Print printType)
        | EMail -> Sync this.EMail

    member this.Search model = 
        model.IsOperationInProgress <- true
        model.Items <- repository.InvoicesSearch(model.Filter, model.Last) |> Seq.map EntityModel.Load |> ObservableCollection.ofSeq 

        for x in model.Items do
            x.LineItems <- x.LineItems |> ObservableCollection.deleteEntityOnRemove repository
        model.IsOperationInProgress <- false

    member this.Edit model = 
        async {
            let view = InvoiceDetailsView()
            let controller = InvoiceDetailsController repository
            let mvc = Mvc(model.SelectedInvoice, view, controller)
            let! isSaved = mvc.StartWindow() 
            if not isSaved
            then
                model.SelectedInvoice.DiscardChanges()
        }

    member this.Save model = 
        let invoice = model.SelectedInvoice
        invoice.Validate repository
        if invoice.IsValid
        then
            invoice.Save repository
            invoiceModified <- false

    member this.PreviewLineItemDelete cancel model = 
        if this.DoYouReallyWantToDeleteLineItem model = MessageBoxResult.No 
        then 
            cancel()
        else
            model.SelectedInvoice.Compute()
            invoiceModified <- true
        
    member private this.DoYouReallyWantToDeleteLineItem model = 
        let message = sprintf "Are you sure you want delete line item for product %s, quantity %i" model.SelectedLineItem.UPC.Product.ProductName.Name model.SelectedLineItem.Quantity
        MessageBox.Show(message, "Delete line item", MessageBoxButton.YesNo, MessageBoxImage.Warning, defaultResult = MessageBoxResult.No)

    member this.DeleteLineItem model = 
        if this.DoYouReallyWantToDeleteLineItem model = MessageBoxResult.Yes
        then 
            model.SelectedInvoice.LineItems.Remove(model.SelectedLineItem) |> ignore
            invoiceModified <- true
        
    member this.AddLineItem model = 
        let x = Model.Create()
        let mvc = UpcSearchController.Mvc(x, repository)
        if mvc.StartDialog() 
        then 
            let upc = x.SelectedUPC.Entity
            let li : InvoiceLineItemModel = Model.Create()
            li.UPC <- upc
            let product = upc.Product
            li.BasePrice <- product.ShopCost
            li.Commission <- product.ClientCommission model.SelectedInvoice.Client.Id
            li.Compute()
            model.SelectedInvoice.LineItems.Add li
            model.SelectedLineItem <- li

    member this.SelectedInvoiceChanged previousInvoice = 
        if invoiceModified 
        then
            if MessageBox.ActionConfirmed(sprintf "Invoice %i has been modified. Would you like to save it?" previousInvoice.Id, "Save changes") 
            then 
                previousInvoice.Validate repository
                if previousInvoice.IsValid
                then
                    previousInvoice.Save repository
                else
                    MessageBox.Error(sprintf "Can not save invoice #%i. Validation failed." previousInvoice.Id)
            else
                for deletedLineItem in repository.DeletedLineItems previousInvoice.Entity do
                    repository.Unchanged deletedLineItem
                previousInvoice.DiscardChanges()
                
            invoiceModified <- false

    member this.LineItemModified columnName model =               
        invoiceModified <- true  
        if columnName = "%" then model.SelectedLineItem.IsDefaultCommission <- false

    member private this.GetReportForm(printType, model : InvoiceModel) = 
        ReportForm.Create(
            reportName = printType, 
            parameters = ["invoiceId", string model.SelectedInvoice.Id])

    member this.Print printType model =      
        this.GetReportForm(printType, model).ShowDialog() |> ignore

    member this.EMail model =      
        let view = EMailView()
        let controller = EMailController repository
        let email : EMailModel  = Model.Create()
        let mvc = Mvc(email, view, controller)
        let invoice = model.SelectedInvoice
        let client = invoice.Client
        email.Recipient <- client.EMail
        email.Subject <- sprintf "Attn: %s. Invoice #%i" client.Attn invoice.Id
        model.IsOperationInProgress <- true
        let pdf = this.GetReportForm("Invoice", model).GetPDF()
        email.Attachment <- 
            new Attachment(
                contentStream = new MemoryStream(pdf), 
                name = sprintf "IN#%i.%s.pdf" invoice.Id invoice.Client.CompanyName)
        model.IsOperationInProgress <- false
        mvc.StartDialog() |> ignore

